package ssq.gamest.toolchain;

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import org.junit.Test;

import fri.patterns.interpreter.parsergenerator.semantics.ReflectSemantic;

public class ReflectTreeBuilder extends ReflectSemantic
{
    @Test
    public void treeBuilderTest()
            throws Exception
    {
        RuleParser parser = new RuleParser();
        //        Scanner s = new Scanner(System.in);
        //
        //        for (String input = s.nextLine();; input = s.nextLine())
        //        {
        //            Node node = new RuleParser().getRoot(input);
        //            System.out.println(node);
        //        }
        for (String string : new String[] {
                "#3a<=A+++(#2+=) & #2b.A&c.A & $#_1 | #4a & #2$#2 @_1*15+a",
                "Joker & #2joker",
                "#2a.[A]+++#2+=",
                "#2[~a].[~A]",
                "a.A++#5",
                "#4a & #2$#2",
                "a<=A .A++#5"
        })
        {
            System.out.println(string);
            ssq.gamest.toolchain.ReflectTreeBuilder.Node node = parser.getRoot(string);
            System.out.println(node);
        }
    }

    public Object pattern(Object pokerPattern)
    {
        return pokerPattern;
    }

    public Object pokerPattern(Object pokerPatternExpressionOrElisped)
    {
        PokerPattern result = new PokerPattern();

        if (pokerPatternExpressionOrElisped instanceof String)
        {
            result.ellipsed = true;
        }
        else
        {
            result.pokerPatternExpression = (PokerPatternExpression) pokerPatternExpressionOrElisped;
        }

        return result;
    }

    @SuppressWarnings("unchecked")
    public Object S_pokerPatternEXPRESSION(Object pokerPatternExpression, Object optAssertEquals)
    {
        PokerPatternExpression result = (PokerPatternExpression) pokerPatternExpression;
        try
        {
            result.assertEquals.addAll((Collection<String>) (((List<?>) optAssertEquals).get(1)));
        }
        catch (Exception e)
        {
            try
            {
                result.assertEquals.add((String) (((List<?>) optAssertEquals).get(1)));
            }
            catch (Exception e1)
            {
            }
        }
        
        return result;
    }

    public Object pokerPatternEXPRESSION(Object pokerPatternTerm)
    {
        PokerPatternExpression result = new PokerPatternExpression();
        result.add((PokerPatternTerm) pokerPatternTerm);

        return result;
    }

    public Object pokerPatternEXPRESSION(Object pokerPatternEXPRESSION, Object or, Object pokerPatternTerm)
    {
        ((PokerPatternExpression) pokerPatternEXPRESSION).add((PokerPatternTerm) pokerPatternTerm);

        return pokerPatternEXPRESSION;
    }

    public Object S_EXPRESSIONList(Object expr)
    {
        LinkedList<String> result = new LinkedList<String>();
        result.add((String) expr);
        return result;
    }

    @SuppressWarnings("unchecked")
    public Object S_EXPRESSIONList(Object list, Object comma, Object expr)
    {
        ((LinkedList<String>) list).add((String) expr);
        return list;
    }

    @SuppressWarnings("unchecked")
    public Object S_pokerPatternTERM(Object pokerPatternTERM, Object optAtExp)
    {
        PokerPatternTerm result = new PokerPatternTerm();
        result.pointsWithColor = (LinkedList<PointWithColor>) pokerPatternTERM;

        try
        {
            result.weightExpressions = (LinkedList<String>) (((List<?>) optAtExp).get(1));
        }
        catch (Exception e)
        {
        }

        return result;
    }

    @SuppressWarnings("unchecked")
    public Object pokerPatternTERM(Object pokerPatternTERM, Object and, Object pointWithColor)
    {
        ((List<PointWithColor>) pokerPatternTERM).add((PointWithColor) pointWithColor);

        return pokerPatternTERM;
    }

    public Object pokerPatternTERM(Object pointWithColor)
    {
        List<PointWithColor> result = new LinkedList<PointWithColor>();
        result.add((PointWithColor) pointWithColor);

        return result;
    }

    public Object assertEqual(Object somePointOrColorOrCatchedOrColorvarOrPointvar)
    {
        return somePointOrColorOrCatchedOrColorvarOrPointvar;
    }

    public Object catched(Object underscore, Object num)
    {
        return (String) underscore + (String) num;
    }

    public Object somePointOrColor(Object l, Object var, Object r)
    {
        char tmp = ((String) var).charAt(0);
        if ('a' <= tmp)
        {
            return "somePoint" + (tmp - 'a');
        }
        else
        {
            return "someColor" + (tmp - 'A');
        }
    }

    public Object pointWithColor(Object optLQuantifier, Object point, Object optColor, Object optIncre, Object optRQuantifier)
    {
        PointWithColor result = new PointWithColor();
        result.point = (Point) point;
        try
        {
            result.color = (Color) ((List<?>) optColor).get(1);
        }
        catch (Exception e)
        {
        }

        try
        {
            result.lQuantifier = (Quantifier) optLQuantifier;
        }
        catch (Exception e)
        {
        }

        if (optIncre instanceof String)
        {
            if (((String) optIncre).equals("++"))
            {
                result.incre = true;
                result.byOrder = true;
            }
            else if (((String) optIncre).equals("+++"))
            {
                result.incre = true;
            }
        }

        try
        {
            result.rQuantifier = (Quantifier) optRQuantifier;
        }
        catch (Exception e)
        {
        }

        return result;
    }

    int catchIdCnt = 1;

    public Object quantifier(Object lpOrSharp, Object expressionOrQuantifier, Object rpOrOptQ) throws Exception
    {
        if (expressionOrQuantifier instanceof Quantifier)
        {
            ((Quantifier) expressionOrQuantifier).catchId = catchIdCnt++;

            return expressionOrQuantifier;
        }
        else
        {
            Quantifier result = new Quantifier();

            try
            {
                result.inequality = Inequality.myValueOf((String) rpOrOptQ);
            }
            catch (Exception e)
            {
            }
            result.expression = (String) expressionOrQuantifier;

            return result;
        }
    }

    public Object pointBound(Object C, Object valOrSomeOrVar) throws Exception
    {
        PointBound result = new PointBound();
        result.inequality = Inequality.myValueOf((String) C);

        if (valOrSomeOrVar instanceof String)
        {
            char content = ((String) valOrSomeOrVar).charAt(0);

            if (content == '$')
            {
                throw new Exception("$ not permitted here!");
            }
            else if (content >= 'a' && content <= 'z') //var
            {
                result.isVar = true;
                result.index = content - 'a';
            }
            else
            {
                result.isVal = true;
                result.index = getPointVal(valOrSomeOrVar);
            }
        }
        else
        {
            List<?> tmpList = (List<?>) valOrSomeOrVar;
            if (tmpList.get(1) != null && tmpList.get(1).equals("~"))
            {
                throw new Exception("~ not permitted here!");
            }
            result.isVal = false;
            result.index = (Integer) tmpList.get(2) - 'a';
        }
        return result;
    }

    public Object point(Object valOrSome)
    {
        Point result = new Point();

        if (valOrSome instanceof String)
        {
            result.isVal = true;
            result.index = getPointVal(valOrSome);
        }
        else
        {
            List<?> tmpList = (List<?>) valOrSome;
            result.isSome = true;
            result.index = ((String) tmpList.get(2)).charAt(0) - 'a';
            result.not = "~".equals(tmpList.get(1));
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    public Object point(Object pointVarWithWild, Object pointBounds)
    {
        Point result = new Point();

        if (pointVarWithWild.equals("$"))
        {
            result.isAny = true;
        }
        else
        {
            result.index = ((String) pointVarWithWild).charAt(0) - 'a';
        }

        if (pointBounds instanceof PointBound)
        {
            result.pointBounds = new LinkedList<PointBound>();
            result.pointBounds.add((PointBound) pointBounds);
        }
        else
        {
            result.pointBounds = (List<PointBound>) pointBounds;
        }

        return result;
    }

    public Object color(Object valOrVarOrSome)
    {
        Color result = new Color();
        if (valOrVarOrSome instanceof String)
        {
            String string = (String) valOrVarOrSome;
            if (string.length() == 1 && string.toUpperCase().equals(string))
            {
                result.index = string.charAt(0) - 'A';
            }
            else
            {
                result.isVal = true;
                result.index = Arrays.asList(new int[] { 's', 'h', 'c', 'd' }).indexOf(string.charAt(0));
            }
        }
        else
        {
            List<?> list = (List<?>) valOrVarOrSome;
            result.not = "~".equals(list.get(1));
            result.isSome = true;
            result.index = ((String) list.get(2)).charAt(0) - 'A';
        }
        return result;
    }

    public Object pointvarWithWild(Object str)
    {
        return str;
    }

    @SuppressWarnings("unchecked")
    public Object S_EXPRESSION(Object exprList)
    {
        if (exprList instanceof String)
        {
            return exprList;
        }
        else
        {
            List<String> list = (List<String>) exprList;

            StringBuilder builder = new StringBuilder();
            for (String string : list)
            {
                builder.append(string);
            }
            return builder.toString();
        }
    }

    public Object EXPRESSION(Object term)
    {
        return term;
    }

    public Object EXPRESSION(Object l, Object op, Object r)
    {
        return (String) l + (String) op + (String) r;
    }

    public Object TERM(Object term)
    {
        return term;
    }

    public Object TERM(Object l, Object op, Object r)
    {
        return (String) l + (String) op + (String) r;
    }

    public Object FACTOR(Object f)
    {
        char tmp = ((String) f).charAt(0);

        if (tmp >= 'A' && tmp <= 'Z')
        {
            return "settings.colorOrder.indexOf(" + tmp + ")";
        }
        return f;
    }

    public Object FACTOR(Object f, Object s)
    {
        return (String) f + (String) s;
    }

    public Object FACTOR(Object f, Object s, Object t)
    {
        if (f.equals("[")) //是somePoint的缩写形式
        {
            return "somePoint" + (((String) s).charAt(0) - 'a');
        }
        return (String) f + (String) s + (String) t;
    }

    public static class Node
    {

    }

    public static class PokerPatternExpression extends LinkedList<PokerPatternTerm>
    {
        private static final long serialVersionUID = -7855930076486711598L;
        LinkedList<String>        assertEquals     = new LinkedList<String>();
    }

    public static class PokerPatternTerm
    {
        LinkedList<PointWithColor> pointsWithColor = new LinkedList<>();
        LinkedList<String>         weightExpressions;
    }

    public static class PokerPattern extends Node
    {
        PokerPatternExpression pokerPatternExpression;
        boolean                ellipsed = false;
    }

    public static class PointWithColor
    {
        Point      point;
        Color      color;
        Quantifier lQuantifier, rQuantifier;
        boolean    incre   = false;
        boolean    byOrder = false;
    }

    public static class Point extends Node
    {
        boolean          isVal = false, isSome = false, isAny = false, not = false;
        int              index;
        List<PointBound> pointBounds;
    }

    public static class Color extends Node
    {
        boolean isVal = false, isSome = false, not = false;
        int     index;
    }

    public static class PointBound extends Node
    {
        Inequality inequality;
        boolean    isVal = false;
        boolean    isVar = false;
        int        index;
    }

    public enum Inequality
    {
        L("<"), LE("<="), E("=="), GE(">="), G(">");

        private String nameString;

        Inequality(String name)
        {
            nameString = name;
        }

        @Override
        public String toString()
        {
            return nameString;
        }

        public static Inequality myValueOf(String s) throws Exception
        {
            switch (s)
            {
                case "+=":
                case ">=":
                    return GE;

                case "-=":
                case "<=":
                    return LE;

                case "==":
                    return E;

                case ">":
                case "+":
                    return G;

                case "<":
                case "-":
                    return L;
                default:
                    throw new Exception();
            }
        }
    }

    public static class Quantifier extends Node
    {
        int        catchId    = 0;
        String     expression;
        Inequality inequality = Inequality.E;

        public Quantifier()
        {
        }
    }

    protected int getPointVal(Object valOrSome)
    {
        try
        {
            return Integer.valueOf((String) valOrSome);
        }
        catch (NumberFormatException e)
        {
            if (((String) valOrSome).equals("A"))
            {
                return 1;
            }
            else if (((String) valOrSome).equals("J"))
            {
                return 11;
            }
            else if (((String) valOrSome).equals("Q"))
            {
                return 12;
            }
            else if (((String) valOrSome).equals("K"))
            {
                return 13;
            }
            else if (((String) valOrSome).equals("joker"))
            {
                return 14;
            }
            else if (((String) valOrSome).equals("Joker"))
            {
                return 15;
            }
            else
            {
                return -1;
            }
        }
    }
}
